package com.ruoyi.common.utils;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * SA-Token 安全工具类
 *
 * @author ruoyi
 */
public class SaTokenUtils {

    /**
     * 用户ID
     **/
    public static Long getUserId() {
        try {
            return getLoginUser().getUserId();
        } catch (Exception e) {
            throw new NotLoginException("未登录或登录已过期", StpUtil.getLoginType(), "-1");
        }
    }

    /**
     * 获取部门ID
     **/
    public static Long getDeptId() {
        try {
            return getLoginUser().getDeptId();
        } catch (Exception e) {
            throw new NotLoginException("未登录或登录已过期", StpUtil.getLoginType(), "-1");
        }
    }

    /**
     * 获取用户账户
     **/
    public static String getUsername() {
        try {
            return getLoginUser().getUsername();
        } catch (Exception e) {
            throw new NotLoginException("未登录或登录已过期", StpUtil.getLoginType(), "-1");
        }
    }

    /**
     * 获取用户
     **/
    public static LoginUser getLoginUser() {
        try {
            // 使用SA-Token获取登录用户信息
            if (StpUtil.isLogin()) {
                // 从SA-Token会话中获取LoginUser对象
                Object loginUserObj = StpUtil.getSession().get(Constants.LOGIN_USER_KEY);
                if (loginUserObj instanceof LoginUser) {
                    return (LoginUser) loginUserObj;
                } else if (loginUserObj instanceof JSONObject jsonObject) {
                    // 处理JSONObject反序列化为LoginUser
                    return JSON.toJavaObject(jsonObject, LoginUser.class);
                } else if (loginUserObj != null) {
                    // 尝试通过JSON转换
                    String jsonStr = JSON.toJSONString(loginUserObj);
                    return JSON.parseObject(jsonStr, LoginUser.class);
                }
            }
            throw new NotLoginException("未登录或登录已过期", StpUtil.getLoginType(), "-1");
        } catch (Exception e) {
            if (e instanceof NotLoginException) {
                throw e;
            }
            throw new ServiceException("获取用户信息异常");
        }
    }

    /**
     * 设置用户信息到SA-Token会话
     *
     * @param loginUser 登录用户
     */
    public static void setLoginUser(LoginUser loginUser) {
        if (loginUser != null) {
            // 将用户信息存储到SA-Token会话中
            StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginUser);
        }
    }

    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public static boolean hasPermi(String permission) {
        if (StringUtils.isEmpty(permission)) {
            return false;
        }
        // 如果是超级管理员，直接返回true
        if (isAdmin(getUserId())) {
            return true;
        }
        // 使用SA-Token验证权限
        try {
            StpUtil.checkPermission(permission);
            return true;
        } catch (NotPermissionException e) {
            return false;
        }
    }

    /**
     * 验证用户是否拥有某个角色
     *
     * @param role 角色标识
     * @return 用户是否具备某角色
     */
    public static boolean hasRole(String role) {
        if (StringUtils.isEmpty(role)) {
            return false;
        }
        // 如果是超级管理员，直接返回true
        if (isAdmin(getUserId())) {
            return true;
        }
        // 使用SA-Token验证角色
        try {
            StpUtil.checkRole(role);
            return true;
        } catch (NotRoleException e) {
            return false;
        }
    }

    /**
     * 是否为管理员
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId) {
        return userId != null && 1L == userId;
    }

    /**
     * 验证用户是否不具备某角色，与 isRole逻辑相反。
     *
     * @param role 角色名称
     * @return 用户是否不具备某角色
     */
    public static boolean lacksRole(String role) {
        return !hasRole(role);
    }

    /**
     * 验证用户是否具有以下任意一个角色
     *
     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
     * @return 用户是否具有以下任意一个角色
     */
    public static boolean hasAnyRoles(String roles) {
        if (StringUtils.isEmpty(roles)) {
            return false;
        }

        // 如果是超级管理员，直接返回true
        if (isAdmin(getUserId())) {
            return true;
        }

        for (String role : roles.split(Constants.ROLE_DELIMETER)) {
            if (hasRole(role)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否包含权限
     *
     * @param authorities 权限列表
     * @param permission  权限字符串
     * @return 用户是否具备某权限
     */
    public static boolean hasPermi(Collection<String> authorities, String permission) {
        if (CollectionUtils.isEmpty(authorities)) {
            return false;
        }
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || x.equals(StringUtils.trim(permission)));
    }

    /**
     * 判断是否包含角色
     *
     * @param roles 角色列表
     * @param role  角色
     * @return 用户是否具备某角色权限
     */
    public static boolean hasRole(Collection<String> roles, String role) {
        if (CollectionUtils.isEmpty(roles)) {
            return false;
        }
        return roles.stream().filter(StringUtils::hasText)
                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || x.equals(StringUtils.trim(role)));
    }

    /**
     * 获取登录用户的权限列表
     *
     * @return 权限列表
     */
    public static Set<String> getPermissions() {
        LoginUser loginUser = getLoginUser();
        if (loginUser != null && !CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return loginUser.getPermissions();
        }
        return new HashSet<>();
    }

    /**
     * 获取登录用户的角色列表
     *
     * @return 角色列表
     */
    public static Set<String> getRoles() {
        LoginUser loginUser = getLoginUser();
        if (loginUser != null && loginUser.getUser() != null && !CollectionUtils.isEmpty(loginUser.getUser().getRoles())) {
            return loginUser.getUser().getRoles().stream()
                    .map(SysRole::getRoleKey)
                    .collect(Collectors.toSet());
        }
        return new HashSet<>();
    }

    /**
     * 退出登录
     */
    public static void logout() {
        StpUtil.logout();
    }

    /**
     * 获取当前登录用户的token
     *
     * @return token
     */
    public static String getToken() {
        return StpUtil.getTokenValue();
    }

    /**
     * 检查是否已经登录
     *
     * @return 是否已登录
     */
    public static boolean isLogin() {
        return StpUtil.isLogin();
    }

    /**
     * 获取会话剩余时间（单位：秒）
     *
     * @return 会话剩余时间
     */
    public static long getSessionTimeout() {
        return StpUtil.getSessionTimeout();
    }

    /**
     * 续签当前token（将其会话时间设置为全局配置最大值）
     */
    public static void renewTimeout() {
        StpUtil.renewTimeout(StpUtil.getTokenTimeout());
    }

    /**
     * 生成BCrypt加密密码
     *
     * @param password 明文密码
     * @return 加密后的密码
     */
    public static String encryptPassword(String password) {
        return BCrypt.hashpw(password, BCrypt.gensalt());
    }

    /**
     * 验证密码
     *
     * @param plainPassword  明文密码
     * @param hashedPassword 哈希密码
     * @return 是否匹配
     */
    public static boolean matchesPassword(String plainPassword, String hashedPassword) {
        return BCrypt.checkpw(plainPassword, hashedPassword);
    }

}